import {
  Injectable,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Song } from './song.entity';
import {
  CreateSongDto,
  UpdateSongDto,
  SongResponseDto,
  SongsPaginationQueryDto,
  PaginationResponseDto,
  SongsByCategoryQueryDto,
} from './song.dto';
import { User } from '../user/user.entity';
import { SongLike } from './song-like.entity';
import { SongCollection } from './song-collection.entity';
import { Category } from '../category/category.entity';
import { Singer } from '../singer/singer.entity';
import { Album } from '../album/album.entity';

@Injectable()
export class SongService {
  constructor(
    @InjectRepository(Song) private songRepository: Repository<Song>,
    @InjectRepository(User) private userRepository: Repository<User>,
    @InjectRepository(Category)
    private categoryRepository: Repository<Category>,
    @InjectRepository(Singer)
    private singerRepository: Repository<Singer>,
    @InjectRepository(Album)
    private albumRepository: Repository<Album>,
  ) {}

  async createSong(
    createSongDto: CreateSongDto,
    userId?: number,
  ): Promise<SongResponseDto> {
    // 创建新歌曲
    if (!createSongDto.genre) {
      createSongDto.genre = '未知';
    }
    if (!createSongDto.duration) {
      createSongDto.duration = 10;
    }
    const song = new Song();
    song.title = createSongDto.title;
    song.genre = createSongDto.genre;
    song.duration = createSongDto.duration;
    song.audioUrl = createSongDto.audioUrl;
    song.coverImageUrl = createSongDto.coverImageUrl as string;
    song.lyrics = createSongDto.lyrics as string;

    // 关联歌手
    if (createSongDto.artistId) {
      const singer = await this.singerRepository.findOne({
        where: { id: createSongDto.artistId },
      });
      if (!singer) {
        throw new BadRequestException('歌手不存在');
      }
      song.artist = singer;
    } else {
      throw new BadRequestException('歌手ID不能为空');
    }

    // 关联专辑
    if (createSongDto.albumId) {
      const album = await this.albumRepository.findOne({
        where: { id: createSongDto.albumId },
      });
      if (album) {
        song.album = album;
      }
    }

    // 如果有用户ID，关联上传用户
    if (userId) {
      const user = await this.userRepository.findOne({ where: { id: userId } });
      if (user) {
        song.uploadedBy = user;
      }
    }

    // 如果有分类ID，关联分类
    if (createSongDto.categoryIds && createSongDto.categoryIds.length > 0) {
      const categories = await this.categoryRepository.findByIds(
        createSongDto.categoryIds,
      );
      if (categories.length !== createSongDto.categoryIds.length) {
        throw new BadRequestException('部分分类不存在');
      }
      song.categories = categories;
    }

    await this.songRepository.save(song);

    // 返回歌曲信息
    return this.mapSongToResponseDto(song);
  }

  async findAllSongs(
    genre?: string,
    artist?: string,
    album?: string,
    searchTerm?: string,
    page?: number,
    limit?: number,
  ): Promise<SongResponseDto[]> {
    const query = this.songRepository.createQueryBuilder('song');
    query.leftJoinAndSelect('song.categories', 'categories');
    query.leftJoinAndSelect('song.artist', 'artist');
    query.leftJoinAndSelect('song.album', 'album');

    // 添加筛选条件
    if (genre) {
      query.andWhere('song.genre = :genre', { genre });
    }

    if (artist) {
      // query.leftJoin('song.artist', 'singer');
      query.andWhere('artist.name LIKE :artist', { artist: `%${artist}%` });
    }

    if (album) {
      query.andWhere('album.title LIKE :album', { album: `%${album}%` });
    }

    if (searchTerm) {
      query.leftJoin('song.artist', 'singer');
      query.andWhere(
        'song.title LIKE :searchTerm OR singer.name LIKE :searchTerm OR album.title LIKE :searchTerm',
        { searchTerm: `%${searchTerm}%` },
      );
    }

    // 按播放量降序排序
    query.orderBy('song.plays', 'DESC');
    query.andWhere('song.isDeleted = false');

    // 应用分页
    if (page && limit) {
      const offset = (page - 1) * limit;
      query.skip(offset).take(limit);
    }

    const songs = await query.getMany();
    return songs.map((song) => this.mapSongToResponseDto(song));
  }

  /**
   * 获取歌曲总数（可带筛选条件）
   */
  async getSongsCount(
    genre?: string,
    artist?: string,
    album?: string,
    searchTerm?: string,
  ): Promise<number> {
    const query = this.songRepository.createQueryBuilder('song');

    // 添加筛选条件
    if (genre) {
      query.andWhere('song.genre = :genre', { genre });
    }

    if (artist) {
      query.andWhere('song.artist = :artist', { artist });
    }

    if (album) {
      query.andWhere('song.album = :album', { album });
    }

    if (searchTerm) {
      query.andWhere(
        'song.title LIKE :searchTerm OR song.artist LIKE :searchTerm OR song.album LIKE :searchTerm',
        { searchTerm: `%${searchTerm}%` },
      );
    }
    query.andWhere('song.isDeleted = false');
    return await query.getCount();
  }

  /**
   * 获取分页歌曲列表
   */
  async findSongsWithPagination(
    queryDto: SongsPaginationQueryDto,
  ): Promise<PaginationResponseDto<SongResponseDto>> {
    const { page = 1, limit = 10, genre, artist, album, searchTerm } = queryDto;

    // 获取分页数据
    const songs = await this.findAllSongs(
      genre,
      artist,
      album,
      searchTerm,
      page,
      limit,
    );

    // 获取总数
    const total = await this.getSongsCount(genre, artist, album, searchTerm);

    // 计算分页元数据
    const totalPages = Math.ceil(total / limit);
    const hasNextPage = page < totalPages;
    const hasPreviousPage = page > 1;

    return {
      data: songs,
      meta: {
        total,
        page,
        limit,
        totalPages,
        hasNextPage,
        hasPreviousPage,
      },
    };
  }

  /**
   * 通过分类ID获取歌曲列表
   * 如果categoryId为undefined，则返回所有分类的歌曲
   */
  async findSongsByCategory(
    queryDto: SongsByCategoryQueryDto,
  ): Promise<PaginationResponseDto<SongResponseDto>> {
    const { categoryId, page = 1, limit = 10 } = queryDto;

    // 查询构建
    const query = this.songRepository
      .createQueryBuilder('song')
      .leftJoinAndSelect('song.categories', 'category')
      .leftJoinAndSelect('song.artist', 'artist')
      .leftJoinAndSelect('song.album', 'album')
      .orderBy('song.plays', 'DESC')
      .andWhere('song.isDeleted = false');

    // 获取总数的查询构建
    const totalQuery = this.songRepository.createQueryBuilder('song');

    // 如果提供了categoryId，验证分类是否存在并添加分类筛选条件
    if (categoryId !== undefined) {
      const category = await this.categoryRepository.findOne({
        where: { id: categoryId },
      });
      if (!category) {
        throw new BadRequestException('分类不存在');
      }

      query.where('category.id = :categoryId', { categoryId });
      totalQuery
        .leftJoin('song.categories', 'category')
        .where('category.id = :categoryId', { categoryId })
        .andWhere('song.isDeleted = false');
    } else {
      // 如果没有提供categoryId，确保查询包含所有分类的歌曲
      totalQuery.leftJoin('song.categories', 'category');
    }

    // 应用分页
    const offset = (page - 1) * limit;
    query.skip(offset).take(limit);

    // 获取歌曲总数
    const total = await totalQuery.getCount();

    // 获取分页数据
    const songs = await query.getMany();

    // 计算分页元数据
    const totalPages = Math.ceil(total / limit);
    const hasNextPage = page < totalPages;
    const hasPreviousPage = page > 1;

    return {
      data: songs.map((song) => this.mapSongToResponseDto(song)),
      meta: {
        total,
        page,
        limit,
        totalPages,
        hasNextPage,
        hasPreviousPage,
      },
    };
  }

  async findSongById(id: number): Promise<SongResponseDto> {
    const song = await this.songRepository.findOne({
      where: { id },
      relations: ['uploadedBy', 'categories'],
    });

    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }

    return this.mapSongToResponseDto(song);
  }

  async updateSong(
    id: number,
    updateSongDto: UpdateSongDto,
  ): Promise<SongResponseDto> {
    const song = await this.songRepository.findOne({
      where: { id },
      relations: ['uploadedBy', 'categories', 'artist', 'album'],
    });

    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }

    // 创建一个临时对象，不包含artistId和albumId
    const { artistId, albumId, ...basicInfo } = updateSongDto;

    // 更新基本歌曲信息
    Object.assign(song, basicInfo);

    // 处理歌手更新
    if (artistId !== undefined) {
      if (artistId === null) {
        throw new BadRequestException('歌手ID不能为空');
      }
      const artist = await this.singerRepository.findOneBy({ id: artistId });
      if (!artist) {
        throw new NotFoundException(`ID为${artistId}的歌手不存在`);
      }
      song.artist = artist;
    }

    // 处理专辑更新
    if (albumId !== undefined) {
      if (albumId === null) {
        // 将专辑设置为null需要特殊处理，因为TypeORM的类型定义问题
        // 这里我们通过Repository API来处理
        await this.songRepository
          .createQueryBuilder()
          .update(Song)
          .set({ album: null })
          .where({ id })
          .execute();
      } else {
        const album = await this.albumRepository.findOneBy({ id: albumId });
        if (!album) {
          throw new NotFoundException(`ID为${albumId}的专辑不存在`);
        }
        song.album = album;
      }
    }

    // 如果提供了新的分类ID，更新分类关联
    if ('categoryIds' in updateSongDto) {
      if (updateSongDto.categoryIds && updateSongDto.categoryIds.length > 0) {
        const categories = await this.categoryRepository.findByIds(
          updateSongDto.categoryIds,
        );
        if (categories.length !== updateSongDto.categoryIds.length) {
          throw new BadRequestException('部分分类不存在');
        }
        song.categories = categories;
      } else {
        // 如果categoryIds为空数组，则清空分类
        song.categories = [];
      }
    }
    await this.songRepository.save(song);

    return this.mapSongToResponseDto(song);
  }

  async deleteSong(id: number): Promise<void> {
    // 软删除
    const result = await this.songRepository.update(id, { isDeleted: true });
    if (result.affected === 0) {
      throw new NotFoundException('歌曲不存在');
    }
  }

  async incrementPlays(id: number): Promise<void> {
    const song = await this.songRepository.findOne({ where: { id } });
    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }
    song.plays += 1;
    await this.songRepository.save(song);
  }

  async toggleLike(
    id: number,
    userId: number,
  ): Promise<{ likes: number; isLiked: boolean }> {
    const song = await this.songRepository.findOne({ where: { id } });
    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }

    const user = await this.userRepository.findOne({ where: { id: userId } });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    // 检查用户是否已经点赞了这首歌
    const queryRunner =
      this.songRepository.manager.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 查找现有的点赞记录
      const existingLike = await queryRunner.manager.findOne(SongLike, {
        where: { song: { id }, user: { id: userId } },
      });

      let isLiked = false;
      if (existingLike) {
        // 如果已点赞，则取消点赞
        await queryRunner.manager.remove(existingLike);
        song.likes = Math.max(0, song.likes - 1);
      } else {
        // 如果未点赞，则添加点赞
        const newLike = new SongLike();
        newLike.song = song;
        newLike.user = user;
        await queryRunner.manager.save(newLike);
        song.likes += 1;
        isLiked = true;
      }

      await queryRunner.manager.save(song);
      await queryRunner.commitTransaction();

      return { likes: song.likes, isLiked };
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  async toggleCollection(
    id: number,
    userId: number,
  ): Promise<{ collections: number; isCollected: boolean }> {
    const song = await this.songRepository.findOne({ where: { id } });
    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }

    const user = await this.userRepository.findOne({ where: { id: userId } });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    // 检查用户是否已经收藏了这首歌
    const queryRunner =
      this.songRepository.manager.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 查找现有的收藏记录
      const existingCollection = await queryRunner.manager.findOne(
        SongCollection,
        {
          where: { song: { id }, user: { id: userId } },
        },
      );

      let isCollected = false;
      if (existingCollection) {
        // 如果已收藏，则取消收藏
        await queryRunner.manager.remove(existingCollection);
        song.collections = Math.max(0, song.collections - 1);
      } else {
        // 如果未收藏，则添加收藏
        const newCollection = new SongCollection();
        newCollection.song = song;
        newCollection.user = user;
        await queryRunner.manager.save(newCollection);
        song.collections += 1;
        isCollected = true;
      }

      await queryRunner.manager.save(song);
      await queryRunner.commitTransaction();

      return { collections: song.collections, isCollected };
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  // 查询歌曲是否被用户收藏和点赞
  async getSongStatus(
    songId: number,
    userId: number,
  ): Promise<{
    isLiked: boolean;
    isCollected: boolean;
    likes: number;
    collections: number;
  }> {
    const song = await this.songRepository.findOne({ where: { id: songId } });
    if (!song) {
      throw new NotFoundException('歌曲不存在');
    }

    // 检查是否点赞
    const isLiked = !!(await this.songRepository.manager.findOne(SongLike, {
      where: { song: { id: songId }, user: { id: userId } },
    }));

    // 检查是否收藏
    const isCollected = !!(await this.songRepository.manager.findOne(
      SongCollection,
      {
        where: { song: { id: songId }, user: { id: userId } },
      },
    ));

    return {
      isLiked,
      isCollected,
      likes: song.likes,
      collections: song.collections,
    };
  }

  // 获取热门歌曲列表
  async getTopSongs(
    limit: number = 50,
    timeRange?: 'day' | 'week' | 'month',
  ): Promise<SongResponseDto[]> {
    const query = this.songRepository.createQueryBuilder('song');

    // 添加歌手和专辑的关联查询
    query
      .leftJoinAndSelect('song.artist', 'artist')
      .leftJoinAndSelect('song.album', 'album');

    // 可选的时间范围筛选
    if (timeRange) {
      const now = new Date();
      let startTime: Date;

      switch (timeRange) {
        case 'day':
          startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000);
          break;
        case 'week':
          startTime = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
          break;
        case 'month':
          startTime = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
          break;
        default:
          startTime = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
      }

      // 这里需要一个updatedAt字段来筛选时间范围
      // 实际项目中可能需要一个专门的播放记录日志表来统计
      query.andWhere('song.updatedAt > :startTime', { startTime });
    }

    // 按播放量降序排序，取前N条
    query.orderBy('song.plays', 'DESC').take(limit);

    const topSongs = await query.getMany();
    return topSongs.map((song) => this.mapSongToResponseDto(song));
  }

  // 每日歌曲推荐
  async getDailyRecommendations(
    limit: number = 20,
  ): Promise<SongResponseDto[]> {
    // 获取所有歌曲
    const query = this.songRepository.createQueryBuilder('song');
    // 筛选出未被删除的歌曲
    query.andWhere('song.isDeleted = :isDeleted', { isDeleted: false });
    const allSongs = await query.getMany();

    if (allSongs.length === 0) {
      return [];
    }

    // 使用当前日期作为种子，确保每天的推荐不同
    const today = new Date();
    const dateSeed =
      today.getFullYear() * 10000 +
      (today.getMonth() + 1) * 100 +
      today.getDate();

    // 基于日期种子打乱歌曲顺序
    // 实现Fisher-Yates洗牌算法的一个变体
    const shuffledSongs = [...allSongs];
    for (let i = shuffledSongs.length - 1; i > 0; i--) {
      // 使用日期种子生成伪随机数
      const j = (dateSeed + i * 31) % (i + 1);
      [shuffledSongs[i], shuffledSongs[j]] = [
        shuffledSongs[j],
        shuffledSongs[i],
      ];
    }

    // 取前N首歌曲作为今日推荐
    // 优先选择热度较高的歌曲
    const heatSortedSongs = shuffledSongs
      .map((song) => {
        const now = new Date();
        const hoursSinceCreated =
          (now.getTime() - song.createdAt.getTime()) / (1000 * 60 * 60);
        const timeDecayFactor = Math.max(0.1, 1 - hoursSinceCreated / 168);
        const heatScore = song.plays + song.likes * 2 * timeDecayFactor;
        return { ...song, heatScore };
      })
      .sort((a, b) => b.heatScore - a.heatScore)
      .slice(0, limit);

    return heatSortedSongs.map((song) =>
      this.mapSongToResponseDto(song as Song),
    );
  }

  // 高级热度算法（综合播放量、点赞数和时间衰减）
  async getTrendingSongs(limit: number = 50): Promise<SongResponseDto[]> {
    const query = this.songRepository.createQueryBuilder('song');

    // 选择所有歌曲进行热度计算
    const songs = await query.getMany();

    // 计算热度分数
    const songsWithScore = songs.map((song) => {
      const now = new Date();
      const hoursSinceCreated =
        (now.getTime() - song.createdAt.getTime()) / (1000 * 60 * 60);

      // 简单热度算法：播放量 + 点赞数 * 权重 - 时间衰减
      // 新发布的歌曲会有更高的权重
      const timeDecayFactor = Math.max(0.1, 1 - hoursSinceCreated / 168); // 一周内权重较高
      const heatScore = song.plays + song.likes * 2 * timeDecayFactor;

      return {
        ...song,
        heatScore,
      };
    });

    // 按热度分数排序并返回
    songsWithScore.sort((a, b) => b.heatScore - a.heatScore);

    return songsWithScore
      .slice(0, limit)
      .map((song) => this.mapSongToResponseDto(song as Song));
  }

  private mapSongToResponseDto(song: Song): SongResponseDto {
    const {
      id,
      title,
      artist,
      album,
      genre,
      duration,
      audioUrl,
      coverImageUrl,
      lyrics,
      plays,
      likes,
      createdAt,
      updatedAt,
      uploadedBy,
      categories,
    } = song;
    return {
      id,
      title,
      artist: artist
        ? { id: artist.id, name: artist.name }
        : { id: 0, name: '未知歌手' },
      album: album ? { id: album.id, title: album.title } : undefined,
      genre,
      duration,
      audioUrl,
      coverImageUrl: album?.coverImageUrl || coverImageUrl,
      lyrics,
      plays,
      likes,
      createdAt,
      updatedAt,
      uploadedBy: uploadedBy
        ? { id: uploadedBy.id, username: uploadedBy.username }
        : undefined,
      categories: categories
        ? categories.map((category) => ({
            id: category.id,
            name: category.name,
          }))
        : undefined,
    };
  }
}
